﻿using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;

using System.Diagnostics;
using System.Drawing.Imaging;

namespace WinFormsAppCV
{
    internal class EmguCVImageMatcher
    {
        static EmguCVImageMatcher()
        {
            // 在程序初始化时设置环境变量
            Environment.SetEnvironmentVariable("OPENCV_OPENMP_THREADS", Environment.ProcessorCount.ToString());
            // 通过环境变量强制开启优化（需在程序启动时设置）
            Environment.SetEnvironmentVariable("OPENCV_CPU_DISABLE", "0");  // 0=启用优化，1=禁用‌:ml-citation{ref="5,8" data="citationList"}
        }

        /// <summary>
        /// 钩子
        /// </summary>
        readonly Action<string> Echo;

        internal EmguCVImageMatcher(Action<string> action)
        {
            this.Echo = action;
        }

        private const double SIMILARITY_THRESHOLD = 0.8; // 80% 相似度

        private static readonly Dictionary<string, Mat> cacheMat = [];

        internal InputSimulator MatchImg(string targetImagePath)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();

            // 1. 加载目标图像
            Mat targetMat;
            if (cacheMat.TryGetValue(targetImagePath, out var mat))
            {
                targetMat = mat;
            }
            else
            {
                //using 
                //targetMat = CvInvoke.Imread(targetImagePath, ImreadModes.Color);
                targetMat = CvInvoke.Imread(targetImagePath, ImreadModes.Grayscale);
                if (targetMat.IsEmpty)
                {
                    Echo("错误：无法加载目标图像");
                    return new(Echo);
                }

                //若颜色信息非必要，直接使用 ‌单通道灰度图‌ 进行计算，内存占用减少 2/3
                //CvInvoke.CvtColor(targetMat, targetMat, ColorConversion.Bgr2Gray);

                cacheMat.Add(targetImagePath, targetMat);
            }

            // 2. 截取屏幕
            using Bitmap screenBitmap = CaptureScreen();
            using Image<Bgr, byte> screenImage = BitmapToEmguImage(screenBitmap); // 转换方法
                                                                                  // 3. 执行模板匹配
            using Mat resultMatrix = new();
            //若需更高性能，降采样：
            //CvInvoke.Resize(screenImage.Mat, screenImage.Mat, new Size(), 0.5, 0.5);
            //CvInvoke.Resize(targetMat, targetMat, new Size(), 0.5, 0.5);
            CvInvoke.MatchTemplate(
                screenImage.Mat,
                targetMat,
                resultMatrix,
                TemplateMatchingType.CcoeffNormed
            );

            // 4. 获取最佳匹配位置
            double minVal = 0, maxVal = 0;
            Point minLoc = new(), maxLoc = new();
            CvInvoke.MinMaxLoc(resultMatrix, ref minVal, ref maxVal, ref minLoc, ref maxLoc);

            // 5. 判断相似度
            if (maxVal >= SIMILARITY_THRESHOLD)
            {
                int centerX = maxLoc.X + targetMat.Width / 2;
                int centerY = maxLoc.Y + targetMat.Height / 2;

                // 计算目标区域矩形
                var targetRect = new Rectangle(
                    maxLoc.X,
                    maxLoc.Y,
                    targetMat.Width,
                    targetMat.Height
                );
                MainForm.Queue.Enqueue(targetRect);

                InputSimulator inputSimulator = new(Echo)
                {
                    Point = new Point(centerX, centerY)
                };

                stopwatch.Stop();
                Echo($"本次耗时:{stopwatch.Elapsed.TotalSeconds}s");

                return inputSimulator;
            }
            else
            {
                Echo($"未找到目标 (最高相似度: {maxVal:P0})");

                stopwatch.Stop();
                Echo($"本次耗时:{stopwatch.Elapsed.TotalSeconds}s");

                return new(Echo);
            }
        }

        /// <summary>
        /// 关键方法：将 Bitmap 转换为 Emgu.CV 图像
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        private static Image<Bgr, byte> BitmapToEmguImage(Bitmap bitmap)
        {
            // 确保像素格式为 24bpp RGB
            if (bitmap.PixelFormat != PixelFormat.Format24bppRgb)
            {
                Bitmap converted = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format24bppRgb);
                using (Graphics g = Graphics.FromImage(converted))
                {
                    g.DrawImage(bitmap, 0, 0);
                }
                bitmap.Dispose();
                bitmap = converted;
            }

            // 通过 LockBits 直接构造 Emgu.CV 图像
            BitmapData data = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadOnly,
                PixelFormat.Format24bppRgb
            );

            try
            {
                // 手动创建 Image<Bgr, byte>
                //ColorConversion.Bgr2Rgb有颜色
                //Bgr2Gray无颜色
                Image<Bgr, byte> emguImage = new Image<Bgr, byte>(bitmap.Width, bitmap.Height);
                CvInvoke.CvtColor(new Mat(bitmap.Height, bitmap.Width, DepthType.Cv8U, 3, data.Scan0, data.Stride),
                    emguImage.Mat,
                    ColorConversion.Bgr2Gray); // 注意 OpenCV 默认使用 BGR 顺序
                return emguImage;
            }
            finally
            {
                bitmap.UnlockBits(data);
            }
        }

        /// <summary>
        /// 截屏
        /// </summary>
        /// <returns></returns>
        private static Bitmap CaptureScreen()
        {
            Rectangle bounds = Screen.PrimaryScreen!.Bounds;
            Bitmap bitmap = new(bounds.Width, bounds.Height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size);
            }
            return bitmap;
        }
    }
}
